<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>Writing BHF Services</title>
    <base href="http://bhs.googlecode.com/svn/trunk/"><!--[if IE]></base><![endif]-->
</head>
<body bgcolor="white">
<h1>Writing JSON Services</h1>
<h2>A Service Is A?</h2>
<p>A Service, for our purposes, is a stateless, server side object that has one or more methods that may be invoked
remotely. A Service method takes a single, possibly composite argument and returns a single, possibly
composite result or throws an exception. A JSON service uses JSON to express the incoming argument to the
Service method, the result, and any exceptions that might be thrown in the process. To add a BHF Service to
your Web application involves four steps: web.xml, Module, Initialization, and the Service itself.</p>
<p><a href="javadocs/org/bhf/json/package-summary.html">You should understand the BHF JSON library before writing
JSON services.</a></p>
<h2>web.xml</h2>
You must add a Controller (implemented as a filter) to your BHF application, as shown below. The Controller intercepts
BHF bound requests and routes them to the appropriate Service. This example also shows a listener used to initialize
the application (Facilities and Modules). You can use any mehod you like to initialize the applicaion.
<pre><code>
    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
    &lt;web-app version="2.4"
             xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" &gt;

        &lt;listener&gt;
            &lt;listener-class&gt;com.acme.app.Application&lt;/listener-class&gt;
        &lt;/listener&gt;

        &lt;filter&gt;
            &lt;filter-name&gt;Controller&lt;/filter-name&gt;
            &lt;filter-class&gt;org.bhf.service.Controller&lt;/filter-class&gt;
        &lt;/filter&gt;

        &lt;filter-mapping&gt;
            &lt;filter-name&gt;Controller&lt;/filter-name&gt;
            &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
        &lt;/filter-mapping&gt;

    &lt;/web-app&gt;
</code></pre>
<h2>Module</h2>
A Module binds together some set of Services and can provide some common behavior, such as exception handling.
<pre><code>
    package example;

    import org.bhf.annotations.ModuleInfo;
    import org.bhf.service.Module;
    import org.bhf.service.ProcessView;
    import org.bhf.service.JSONExceptionProcessView;
    import org.bhf.service.IllegalRequestException;

    import java.net.HttpURLConnection;

    @ModuleInfo(
        name="service",
        services =
        {
            StatService.class
        }
    )
    /**
     * A simple Module for our JSON Services. It handles exceptions for us and is the point of
     * Service registration.
     */
    public class ServiceModule extends Module
    {
        /**
         * Let IllegalRequestExceptions pass through. This handle is more specific than
         * the general Exception handler, so it takes precendence for an IllegalRequestException;
         *
         * @param e IllegalRequestException
         * @return a JSONExceptionProcessView
         */
        public ProcessView handle( final IllegalRequestException e )
        {
            return new JSONExceptionProcessView( e, HttpURLConnection.HTTP_BAD_REQUEST );
        }

        /**
         * Unify all exception handling to write back a JSON style exception.
         *
         * @param e Exception
         * @return a JSONExceptionProcessView
         */
        public ProcessView handle( final Exception e )
        {
            return new JSONExceptionProcessView( e );
        }

        /**
         * Handle an exception with i18n messages
         * @param me Message exception
         * @return a JSONExceptionProcessView
         */
        public ProcessView handle( final MessagesException me )
        {
            return new ErrorsProcessView( me.getMessages().getFlatMessages(), me.getCause() );
        }
    }    
</code></pre>
In this case, we have chosen to unify exception handling for all Services of this Module to return a JSON
exception (name,message values) if a sevice throws an Exception. The <code>IllegalRequestException</code> is
handled specially to set the HTTP status to 400 instead of 500, the default on exception. A Service can
override Module level exception handling by providing its own exception handlers. An exception handler
must be a public method named <code>handle</code>, return a <code>ProcessView</code>, and take a single
argument assignable to <code>Throwable</code>. The most specific handler is used for any given situation.
<h2>Application Initialization</h2>
You application must initialize a Configuration Facility, Routing Facility and instantiate each Module, which makes
the Module known to the invocation router. If your application uses Widgets or Pages, you must also initialize a
View Resolver Facility. For example,
<code><pre>
    public class Application implements ServletContextListener
    {
        public void contextInitialized( final ServletContextEvent servletContextEvent )
        {
            try
            {
                ...
                Facilities.bind( ConfigurationFacility.class, FileConfiguration.class );
                Facilities.bind( ViewResolver.class, I18nViewResolver.class );
                Facilities.bind( URLRouter.class, DefaultURLRouter.class );

                new AnonymousModule( null );
                new AdminModule( null );
                new TokenModule( null );
            }
            catch( final Exception e )
            {
                throw new RuntimeException( e );
            }
        }
        ...
    }
</pre></code>
<h2>Service</h2>
A Service has at least a name, assigned by annotation, and at least one Service Method. A Service Method must be a
public method, return an object suitable for JSON marshalling, and take zero or one concrete arguments. The type
of argument must be suitable for <a href="javadocs/org/bhf/json/package-summary.html">JSON unmarshalling</a>.
<pre><code>
    /**
     * A Service has at least one Service Method that may be invoked and is stateless
     * (unlike a Component, which has state, events, ....) A Service Method must 1) be public, 2)take zero or
     * one concrete arguments suitable for JSON unmarshalling, and 3) return a result suitable for JSON
     * marshalling back to the client.
     */
    @ServiceName( "stats" )
    public class StatService extends AbstractService
    {
        /**
         * Compute, at great cost, some simple statistics and a histogram
         *
         * @param values Incoming array of numbers
         * @return The computational result
         * @throws IllegalRequestException Bad input
         */
        @ServiceMethod
        public Result   compute( int[] values )
            throws Exception
        {
            if( values == null )
                throw new IllegalRequestException( "values == null" );
            if( values.length == 0 )
                throw new IllegalRequestException( "zero length array" );

            final Result result = new Result();

            for( int x : values )
            {
                result.mean += x;
                result.min = Math.min( result.min, x );
                result.max = Math.max( result.max, x );

                Integer count = result.getHistogram().get( x );
                if( count == null )
                    count = 1;
                else
                    count = count + 1;
                result.getHistogram().put( x, count );
            }
            result.mean = result.mean / values.length;

            return result;
        }

        /**
         * A simple service result, suitable for JSON marshalling to the client
         */
        public static class Result
        {
            double                  mean = 0;
            int                     min = Integer.MAX_VALUE;
            int                     max = Integer.MIN_VALUE;
            Map&lt;Integer,Integer&gt;    histogram = new TreeMap&lt;Integer,Integer&gt;();

            public double getMean()
            {
                return mean;
            }

            public int getMin()
            {
                return min;
            }

            public int getMax()
            {
                return max;
            }

            public Map&lt;Integer, Integer&gt; getHistogram()
            {
                return histogram;
            }
        }
    }
</code></pre>
<h2>ProcessView</h2>
<p>
    By default, the return result of a Service method is wrapped in whatever <code>ProcessView</code> is returned
    by the <code>newProcessView( Object )</code> method of the Service. (This method is declared on the <code>Service</code>
    interface; <code>AbstractService</code> provides a default implementation that returns a <code>JSONProcessView</code>.)
    Your Service method can return a custom <code>ProcessView</code> implementation directly if you need more control
    over the rendered response.
</p>
<h2>HttpServletRequest and HttpServletResponse Injection</h2>
<p>
    Occasionally, you will need to access the <code>HttpServletRequest</code> or <code>HttpServletResponse</code>
    to, for example, set a cookie or response status. Simply add a <code>HttpServletRequest</code> or
    <code>HttpServletResponse</code> argument to your service method and the BHF will inject the appropriate
    object.
    <code><pre>
    @ServiceName( "registration" )
    public class RegistrationService extends AbstractService
    {
        ...
        @ServiceMethod
        public void register( final UserRegistrationRecord registrationInfo, final HttpServletRequest request, final HttpServletResponse response )
            throws TokenExpiredException, IOException, ClassNotFoundException, MessagesException, PasswordMatchException
        {
            ...

            // Authenticate
            ...
            final Cookie cookie = new Cookie( AccessToken.COOKIE_NAME, new AccessToken( subject, new Date( System.currentTimeMillis() + limit ) ).encode() );
            cookie.setPath( request.getContextPath() + "/kb" );
            response.addCookie( cookie );
            ...
        }
        ...
    }
    </pre></code>
</p>
<h2>Exception Handling</h2>
<p>
    We have seen how to define exception handlers at the Module level; you can also define exception handlers
    on the Service itself.
    <code><pre>
    @ServiceName( "registration" )
    public class RegistrationService extends AbstractService
    {
        ...
        public ProcessView handle( final PasswordMatchException e )
        {
            return new ErrorsProcessView( getModule().newError( "global", "login.passwordMatch", "login.passwordMatch" ) , e);
        }
        ...
    }
    </pre></code>
    Thrown exceptions are JSON marshalled and returned to the client. Since JavaScript does not have typed exceptions, BHF
    relies on exception property conventions, enforced by the <code>JSONExceptionProcessView</code> and the
    <code>ErrorsProcessView</code> classes.
    <ul>
        <li>A simple exception (<code>JSONExceptionProcessView</code>) has a name property (the unqualified class name of the
            exception) and a message property (the exception message).</li>
        <li>A complex message exception (<code>ErrorsProcessView</code>) has a type property (the unqualified class name of the
            exception) and a messages property (one or more Message object). By covention, if a Message is associated
            with a particular element, such as an input field, the topic of the message indicates the associated element's
            ID. Usually, <code>ErrorsProcessView</code> are the result of a Module fielding a
            <code>MessagesException</code></li>
    </ul>
</p>
<p>See also: <a href="../../bhf/www/docs/calling-services.html">Calling JSON Services</a></p>
</body>
</html>